/*
 * @Author: xxx 
 * @Date: 2023年6月7日17:46:12  
 * @Description :无限循环列表
 * @Last Modified by: xxx
 * @Last Modified time: 2023年6月7日17:46:51
 */
import { Component, ScrollView, UITransform, view, _decorator, Node, instantiate, Vec2, Label, find, Prefab } from "cc";
import UtilTool from "../tools/UtilTool";

/**
 * 滑动方向枚举
 */
export enum ScrollDirEnum {
    Vertical,
    Horizon
}
const { ccclass, property } = _decorator;
 
@ccclass
export default class ScrollHelper extends Component {
    //赋值用的obj
    @property(Prefab)
    item: Prefab = null;

    @property(ScrollView)
    Scroll: ScrollView = null;

    //显示用的content
    @property(Node)
    content: Node = null;

    //方向，0是垂直方向，1是水平方向
    @property(Number)
    dir: Number = 0;

    //间距 x或者y方向item的间距
    @property(Number)
    itemDistance: number = 0;
 
    //滑动的方向
    private scrollDir: ScrollDirEnum = ScrollDirEnum.Vertical;

    //需要显示的item数量
    private num: number;

    //实际生成item数量
    private itemNum: number;

    //需求要求的高度/宽度
    private needSize:number = 0;

    private visibleHeight = 0;  //显示范围高度
    private endFun = null;      //滑动到底部回调
    private itemFun = null;     //刷新数据回调
    private data = null         // 数据

    // item的初始化位置
    private initX = 0
    private initY = 0
    private disY = 0

    start() {
        var eventHandler = new Component.EventHandler();
        eventHandler.target = this.node;
        eventHandler.component = "ScrollHelper";
        eventHandler.handler = "OnScroll";
        this.Scroll.scrollEvents.push(eventHandler);

        this.scrollDir = this.dir as ScrollDirEnum;
    }

    /**
     * 设置数据
     * param init 是否首次加载
     * param data 数据
     * param itemNum item的实际显示个数
     * param endFun 滑动到底部回调
     * param itemFun 滑动到底部回调
     */
    setData(param) {
        this.data =  param.data
        this.num = param.data.length;
        this.itemNum = param.itemNum;
        this.endFun = param.endFun
        this.itemFun = param.itemFun

        if (!param.init) {  // 重置位置
            this.Scroll.stopAutoScroll()
            this.curOffset = this.needSize - this.visibleHeight + this.itemDistance/2
        }
        else {
            if (this.num<this.itemNum) {
                this.itemNum = this.num
            }
        }
        
        this.needSize = this.num * this.itemDistance+this.disY;

        if (this.needSize<this.Scroll.content.getComponent(UITransform).height) {
            this.needSize = this.Scroll.content.getComponent(UITransform).height
        }

        if (this.scrollDir == ScrollDirEnum.Horizon) {
            this.initX = this.itemDistance / 2;
            this.initY = 0;
            this.content.getComponent(UITransform).setContentSize(this.needSize, this.content.getComponent(UITransform).contentSize.height)
        } else {
            this.initX = 0;
            this.content.getComponent(UITransform).setContentSize(this.content.getComponent(UITransform).contentSize.width, this.needSize)
            this.initY = this.needSize-this.itemDistance / 2 - this.disY;
        }

        if (param.init) {
            this.visibleHeight = this.Scroll.getComponent(UITransform).contentSize.height;
            this.Scroll.scrollToTop()

            this.InitObjs();
        }
        else{
            this.refresh();

            // let scrollOffset: Vec2 = this.Scroll.getScrollOffset();
            this.Scroll.scrollToOffset(new Vec2(0,this.curOffset))
            // let scrollOffset2: Vec2 = this.Scroll.getScrollOffset();
        }
        
    }
 
    //初始化可见的item
    public itemsList = new Array();
    InitObjs() {
        let curX = 0;
        let curY = 0;
        this.itemsList = []
        for (let i = 0; i < this.itemNum; i++) {
            let obj = instantiate(this.item);
            obj.parent = this.content;
            obj.active = true;
            if (this.scrollDir == ScrollDirEnum.Horizon) {
                curX = this.initX + this.itemDistance * i;
                // console.error("curX:" + curX);
            }
            else {
                curY = this.initY - this.itemDistance * i;
                // console.error("curY:" + curY);
            }
 
            obj.setPosition(curX, curY)
            this.onRefresh(obj, i, i);
            this.itemsList.push(obj);
        }
    }

    private miniIdx = 0;
    private curOffset = 0;
    OnScroll() {
        //获取滚动视图相对于左上角原点的当前滚动偏移
        let scrollOffset: Vec2 = this.Scroll.getScrollOffset();
        let offest = 0;
        if (this.scrollDir == ScrollDirEnum.Horizon)
            //水平的offset是负数，为什么会有这么sb的设计，将它取反和垂直方向的统一一下
            offest = -scrollOffset.x;
        else
            offest = scrollOffset.y;
        this.curOffset = offest;
        this.refresh();
    }
 
    //强行刷新
    public refresh() {
        let offest = this.curOffset;

        //最大高度，超过该高度，不刷新
        if (offest < 0 || offest + this.visibleHeight > this.needSize) {
            if (offest + this.visibleHeight >= this.needSize) {
                this.endFun && this.endFun()
            }
            return;
        }

        let idx: number = 0;//从0开始
        this.miniIdx = Math.floor(offest / this.itemDistance);

        //miniIdx到maxIdx都会刷新
        for (let i = 0; i < this.itemNum; i++) {
            let obj = this.itemsList[i];
            idx = this.miniIdx + i;
            this.refreshItem(idx, i, obj);
        }
    }
 
    //idx是UI该刷新的第几个元素
    private refreshItem(idx, objIdx, obj) {
        if (idx < 0 || idx >= this.num)
            return;
 
        if (obj == null) {
            console.error("obj为空！");
            return;
        }
        let curX = 0;
        let curY = 0;
        if (this.scrollDir == ScrollDirEnum.Horizon)
            curX = this.initX + this.itemDistance * idx;
        else
            curY = this.initY - this.itemDistance * idx;
        // UtilTool.printLog("idx:" + idx + ",initY:" + this.initY + ",curY:" + curY);
        obj.setPosition(curX,curY);
        this.onRefresh(obj, idx, objIdx);
    }
 
    /**
     * 刷新回调
     * @param obj 
     * @param idx 需求显示的索引
     * @param objIdx 实际的item索引
     */
    private onRefresh(obj, idx:number, objIdx:number) {
        if (this.itemFun)
            this.itemFun(obj, idx, objIdx);
    }
    
}